#include "pthread_pool.h"


//头结点初始化
int listInit(Head_st **ptr)
{
	*ptr = malloc(sizeof(**ptr));
	if(*ptr == NULL)
		return -1;
	(*ptr)->first = NULL;
	(*ptr)->last = NULL;
	(*ptr)->node_number = 0;
}

int listInsert(Head_st **ptr, struct Node data)
{
	list_st *newnode = NULL;
	
	newnode = malloc(sizeof(list_st));
	if (newnode == NULL)
	{
		perror("malloc()");
		exit(1);
	}
	newnode->data.fileTask = data.fileTask;
	strcpy(newnode->data.args.src, data.args.src);
	strcpy(newnode->data.args.dest, data.args.dest);
	newnode->next = NULL;

	if((*ptr)->first == NULL)
	{
		(*ptr)->first = newnode;
		(*ptr)->last = newnode;
		(*ptr)->node_number++;
	}
	else
	{
		(*ptr)->last->next = newnode;
		(*ptr)->last = newnode;
		(*ptr)->node_number++;
	}
}

int initPool(pthread_pool *pool, unsigned int threadNum)
{
	int i;
	
	pthread_mutex_init(&pool->mut, NULL);
	pthread_cond_init(&pool->cond, NULL);
	listInit(&pool->taskList);
	
	pool->tids = malloc(TIDMAX * sizeof(pthread_t));
	if (pool->tids == NULL)
	{
		perror("malloc()");
		exit(1);
	}

	pool->activeThreads = threadNum;
	pool->maxWaitingTask = MAXTASK;
	pool->curWaitingTask = 0;
	pool->shutdown = 0;


	for (i = 0; i < threadNum; i++)
	{
		pthread_create(pool->tids + i, NULL, routine, (void *)pool);
	}
}

list_st *getMaskNode(pthread_pool *pool)
{
	list_st *cur = NULL;
	cur = pool->taskList->first;
	pool->taskList->first = pool->taskList->first->next;
	cur->next = NULL;
	return cur;
}

void *routine(void *args)
{
	list_st *task = NULL;
	pthread_pool *pool = (pthread_pool *)args;
	while (1)
	{
		pthread_mutex_lock(&(pool->mut));
		/* 任务为空并且线程池未结束则等待 */
		while ((pool->curWaitingTask == 0) && (pool->shutdown == false))
		{
			pthread_cond_wait(&(pool->cond), &(pool->mut));
		}
		/* 任务为空并且线程池结束则解锁退出 */
		if ((pool->curWaitingTask == 0) && (pool->shutdown == true))
		{
			pthread_mutex_unlock(&(pool->mut));
			pthread_exit(NULL);
		}
		/* 任务不为空且线程池未结束 */
		task = getMaskNode(pool);
		pool->curWaitingTask--;
		pthread_cond_broadcast(&(pool->cond));
		pthread_mutex_unlock(&(pool->mut));
		task->data.fileTask((void *)(&(task->data.args)));
		free(task);
	}
	pthread_exit(0);
}

int addTask(pthread_pool *pool, struct Node data)
{
	pthread_mutex_lock(&(pool->mut));
	listInsert(&(pool->taskList), data);
	while ((pool->curWaitingTask) > (pool->maxWaitingTask))
		pthread_cond_wait(&(pool->cond), &(pool->mut));
	pool->curWaitingTask += 1;
	pthread_cond_signal(&(pool->cond));
	pthread_mutex_unlock(&(pool->mut));
}

int destroyPool(pthread_pool *pool)
{
	int i;
/*	
	while (1)
	{
		pthread_mutex_lock(&(pool->mut));
		if (pool->curWaitingTask != 0)
		{
			pthread_cond_broadcast(&(pool->cond));
			pthread_cond_wait(&(pool->cond), &(pool->mut));
		}
		if (pool->curWaitingTask == 0) 
		{
			pool->shutdown = 1;
			pthread_cond_broadcast(&(pool->cond));
			pthread_mutex_unlock(&(pool->mut));
			break;
		}
		pthread_mutex_unlock(&(pool->mut));
	}
*/
	pool->shutdown = 1;
	pthread_cond_broadcast(&(pool->cond));
	for (i = 0; i < pool->activeThreads; i++)
	{
		pthread_join(*((pool->tids)+i), NULL);
		pthread_cond_broadcast(&(pool->cond));
	}
	
	pthread_mutex_destroy(&(pool->mut));	
	pthread_cond_destroy(&(pool->cond));	
	free(pool->taskList);
	free(pool->tids);
}


